using System.Collections.Generic;
using System.Linq;
using MarriageFertility.Mcm;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Conversation.Persuasion;

namespace MarriageFertility.Extensions;

public static class HeroExtension
{
    private static Dictionary<Hero, List<Hero>> _sexFriendsDictionary = new();
    private static List<PersuasionAttempt> _previousSexFriendPersuasionAttempts = new();
    private static Dictionary<Hero, bool> _sexFriendPersuasionStarted = new();
    private static List<PersuasionTask> AllReservations;
    
    private static Dictionary<Hero, List<Hero>> SexFriendsDictionary
    {
        get
        {
            if (_sexFriendsDictionary == null) _sexFriendsDictionary = new Dictionary<Hero, List<Hero>>();
            return _sexFriendsDictionary;
        }
    }

    public static List<PersuasionAttempt> PreviousSexFriendPersuasionAttempts
    {
        get
        {
            if (_previousSexFriendPersuasionAttempts == null) _previousSexFriendPersuasionAttempts = new List<PersuasionAttempt>();
            return _previousSexFriendPersuasionAttempts;
        }
    }

    public static Dictionary<Hero, bool> SexFriendPersuasionStarted
    {
        get
        {
            if (_sexFriendPersuasionStarted == null) _sexFriendPersuasionStarted = new Dictionary<Hero, bool>();
            return _sexFriendPersuasionStarted;
        }
    }

    public static Hero ElderSister(this Hero hero)
    {
        return hero.Mother?.Children?.FirstOrDefault(h => h.IsAlive && h.IsFemale && h.Age > hero.Age);
    }

    public static Hero LittleSister(this Hero hero)
    {
        return hero.Mother?.Children?.FirstOrDefault(h => h.IsAlive && h.IsFemale && h.Age < hero.Age);
    }

    public static List<Hero> SexFriends(this Hero hero)
    {
        SexFriendsDictionary.TryGetValue(hero, out List<Hero> friends);
        return friends;
    }
    
    public static int SexFriendsCount(this Hero hero) => SexFriends(hero)?.Count ?? 0;

    public static bool IsSexFriend(this Hero hero, Hero otherHero)
    {
        if (SexFriendsDictionary.ContainsKey(hero))
            return SexFriendsDictionary[hero].Contains(otherHero);
        return false;
    }

    public static void BecomeSexFriend(this Hero hero, Hero otherHero)
    {
        hero.AddSexFriend(otherHero);
        otherHero.AddSexFriend(hero);
    }

    private static void AddSexFriend(this Hero hero, Hero otherHero)
    {
        if (SexFriendsDictionary.ContainsKey(hero))
        {
            if (SexFriendsDictionary[hero].Contains(otherHero)) return;
            SexFriendsDictionary[hero].Add(otherHero);
        }
        else
        {
            SexFriendsDictionary.Add(hero, new List<Hero> { otherHero });
        }
    }

    public static bool CanPregnancy(this Hero hero)
    {
        return hero != null && hero.IsFemale && hero.IsAlive && hero.Age >= MCMSettings.Instance.MinPregnancyAge &&
               hero.Age <= MCMSettings.Instance.MaxPregnancyAge && !hero.IsPregnant;
    }

    public static bool HasWife(this Hero hero)
    {
        bool flag1 = hero.Spouse != null && hero.Spouse.IsFemale && hero.Spouse.IsAlive;
        bool flag2 = hero.ExSpouses?.Count > 0 && hero.ExSpouses.Any(h => h.IsAlive && h.IsFemale);
        return flag1 || flag2;
    }

    public static bool WifeInParty(this Hero hero)
    {
        if (hero.PartyBelongedTo?.MemberRoster == null || !HasWife(hero))
            return false;
        
        bool isSpouseInParty = hero.Spouse != null && hero.PartyBelongedTo.MemberRoster.Contains(hero.Spouse.CharacterObject);

        bool isExSpouseInParty = hero.ExSpouses
            .Where(exSpouse => exSpouse.IsAlive && !exSpouse.IsPrisoner)
            .Any(exSpouse => hero.PartyBelongedTo.MemberRoster.Contains(exSpouse.CharacterObject));

        return isSpouseInParty || isExSpouseInParty;
    }

    public static List<Hero> SpousesInParty(this Hero hero)
    {
        List<Hero> spouses = new List<Hero>();
        if (hero.Spouse != null && hero.Spouse.IsAlive) spouses.Add(hero.Spouse);
        if (hero.ExSpouses != null && hero.ExSpouses.Count > 0)
        {
            spouses.AddRange(hero.ExSpouses.Where(h => h.IsAlive && !h.IsPrisoner && h.CurrentSettlement == hero.CurrentSettlement));
        }
        return spouses;
    }

    public static bool IsWife(this Hero hero, Hero femaleHero)
    {
        return hero.Spouse == femaleHero || (hero.ExSpouses?.Count > 0 && hero.ExSpouses.Contains(femaleHero));
    }

    public static void SyncData(IDataStore dataStore)
    {
        dataStore.SyncData("SexFriendsDictionary", ref _sexFriendsDictionary);
        dataStore.SyncData("PreviousSexFriendPersuasionAttempts", ref _previousSexFriendPersuasionAttempts);
        dataStore.SyncData("SexFriendPersuasionStarted", ref _sexFriendPersuasionStarted);
        dataStore.SyncData("AllReservations", ref AllReservations);

    }
}